package com.hnx.admin.aspects;

import cn.hutool.core.util.ReflectUtil;
import com.hnx.admin.annonation.LoginValid;
import com.hnx.admin.api.service.cache.CacheAPI;
import com.hnx.admin.api.service.login.LoginBeforeValidator;
import com.hnx.admin.api.service.login.LoginLogWriter;
import com.hnx.admin.jwt.JwtUtil;
import com.hnx.admin.redis.RedisCache;
import com.hnx.admin.security.core.SecurityProperties;
import com.hnx.admin.utils.ServletUtil;
import com.hnx.admin.web.exception.UserPasswordLimitException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/*
项目名称： core
创 建 人: 倔强的头发
创建日期： 2025/5/29   10:53:29 
描   述： 登录功能切面
*/
@Aspect
@Component
@RequiredArgsConstructor
public class LoginAspect<T> implements CacheAPI {
    private final LoginBeforeValidator loginBeforeValidator;
    private final RedisCache redisCache;
    private final SecurityProperties securityProperties;
    private final LoginLogWriter loginLogWriter;
    private final JwtUtil jwtUtil;
    @Before("@annotation(loginValid)")
    public void loginValid(JoinPoint jp,  LoginValid loginValid) {
        HttpServletRequest request = ServletUtil.getRequest();
        Object arg = jp.getArgs()[0];
        if(Objects.nonNull(request) && Objects.nonNull(arg)){
            loginBeforeValidator.match(arg);
            String username = ReflectUtil.getFieldValue(arg, "username").toString();
            Integer retryCount = redisCache.getCacheObject(getErrCntKey(username), Integer.class);
            if (retryCount == null)
            {
                retryCount = 0;
            }
            if (retryCount >= Integer.valueOf(securityProperties.getMaxRetryCount()).intValue())
            {
                throw new UserPasswordLimitException(securityProperties.getMaxRetryCount(), securityProperties.getLockTime());
            }
        }
    }
    @AfterThrowing(value = "@annotation(com.hnx.admin.annonation.LoginLog)",throwing = "ex")
    public void toAfterThrow(JoinPoint jp,  Exception ex){
        Object arg = jp.getArgs()[0];
//        HttpServletRequest request = ServletUtil.getRequest();
//        String userKey = jwtUtil.getUserKey(request);
//        System.out.println(userKey);
        String username = ReflectUtil.getFieldValue(arg, "username").toString();
        if(ex instanceof BadCredentialsException){
            Integer retryCount = redisCache.getCacheObject(getErrCntKey(username), Integer.class);
            if (retryCount == null)
            {
                retryCount = 0;
            }
            retryCount = retryCount + 1;
            redisCache.setCacheObject(getErrCntKey(username), retryCount, securityProperties.getLockTime(), TimeUnit.MINUTES);
        }
        loginLogWriter.writeLog(arg,1,ex.getMessage());
    }
    @AfterReturning(value = "@annotation(com.hnx.admin.annonation.LoginLog)",returning = "json")
    public void toAfter(JoinPoint jp, Object json){
//        HttpServletRequest request = ServletUtil.getRequest();
//        String userKey = jwtUtil.getUserKey(request);
//        System.out.println(userKey);
        if (json instanceof Map) {
            Map<?,?> map = (Map<?,?>) json;
            Object arg = jp.getArgs()[0];
            String username = ReflectUtil.getFieldValue(arg, "username").toString();
//            String uuid = ReflectUtil.getFieldValue(arg, "uuid").toString();
            clearLoginRecordCache(username);
            loginLogWriter.writeLog(arg,0,map.get("msg").toString());
        }

    }
    private void clearLoginRecordCache(String loginName)
    {
        if (redisCache.hasKey(getErrCntKey(loginName)))
        {
            redisCache.deleteObject(getErrCntKey(loginName));
        }
    }
}
